// ----------------------------------------------------------------------------
// mutex_impl.apple.h
// ----------------------------------------------------------------------------
#ifndef FW_MUTEX_IMPL_APPLE_H
#define FW_MUTEX_IMPL_APPLE_H
#include <fw/base/core/stdinteger.h>
#include <fw/base/core/assertion.h>
#include <pthread.h>

namespace fw
{
	class MutexImplBase
	{
	protected:
		const char*				m_name;
		pthread_mutex_t			m_mutex;
		
		bool InitializeMutex(int sharedPolicy)
		{
			int ret;
			pthread_mutexattr_t	pma;
			
			ret = pthread_mutexattr_init(&pma);
			FW_ASSERT(ret==0);
			
			ret = pthread_mutexattr_setpshared(&pma, sharedPolicy);
			FW_ASSERT(ret==0);
			
			ret = pthread_mutexattr_settype(&pma, PTHREAD_MUTEX_DEFAULT);
			FW_ASSERT(ret==0);
			
			ret = pthread_mutexattr_setprotocol(&pma, PTHREAD_PRIO_NONE);
			FW_ASSERT(ret==0);
			
			ret = pthread_mutex_init(&m_mutex, &pma);
			FW_ASSERT(ret==0);
			
			ret = pthread_mutexattr_destroy(&pma);
			FW_ASSERT(ret==0);
			
			return true;
		}
		
	public:
		 MutexImplBase(const char* name)
		: m_name(name)
		{
		}
		
		virtual ~MutexImplBase()
		{
			int ret = pthread_mutex_destroy(&m_mutex);
			FW_ASSERT(ret==0);
			FW_UNUSED(ret);
		}
		
		bool Lock()
		{
			int ret = pthread_mutex_lock(&m_mutex);
			if(ret == 0)
			{
				return true;
			}
			// EINVAL or EDEADLK 
			return false;
		}
		
		bool TryLock()
		{
			int ret = pthread_mutex_trylock(&m_mutex);
			if(ret == 0)
			{
				return true;
			}
			// EBUSY ot EINVAL 
			return false;
		}
		
		bool Unlock()
		{
			int ret = pthread_mutex_unlock(&m_mutex);
			if(ret == 0)
			{
				return true;
			}
			return false;
		}
		
	}; // class MutexImplBase 

	class MutexImpl : public MutexImplBase
	{
	public:
		MutexImpl(const char* name)
		: MutexImplBase(name)
		{
			InitializeMutex(PTHREAD_PROCESS_PRIVATE);
		}
		
	}; // class MutexImpl 

} // namespace fw

#endif // FW_MUTEX_IMPL_APPLE_H 
